// Parser.cs
// 
// Copyright (C) 2008 Jean-André Santoni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Astrognome
{
	public abstract class Parser
	{
		public static Hashtable Parse(string output)
		{
			double ascendant = Sanitize(GetPosition("House cusp  1", output, 0) + 180);
			
			Dictionary<string, double> pos = new Dictionary<string, double>();
			pos.Add("Sun",     Sanitize(GetPosition("Sun ", output, ascendant)));
			pos.Add("Moon",    Sanitize(GetPosition("Moon", output, ascendant)));
			pos.Add("Lilith",  Sanitize(GetPosition("Lili", output, ascendant)));
			pos.Add("Node",    Sanitize(GetPosition("Node", output, ascendant)));
			pos.Add("Mercury", Sanitize(GetPosition("Merc", output, ascendant)));
			pos.Add("Venus",   Sanitize(GetPosition("Venu", output, ascendant)));
			pos.Add("Mars",    Sanitize(GetPosition("Mars", output, ascendant)));
			pos.Add("Jupiter", Sanitize(GetPosition("Jupi", output, ascendant)));
			pos.Add("Saturn",  Sanitize(GetPosition("Satu", output, ascendant)));
			pos.Add("Uranus",  Sanitize(GetPosition("Uran", output, ascendant)));
			pos.Add("Neptune", Sanitize(GetPosition("Nept", output, ascendant)));
			pos.Add("Pluto",   Sanitize(GetPosition("Plut", output, ascendant)));
			pos.Add("SNode",   Sanitize(GetPosition("Node", output, ascendant) + 180));
			
			List<KeyValuePair<string, double>> positions = new List<KeyValuePair<string, double>>();
			positions.AddRange(pos);
			positions.Sort(delegate(KeyValuePair<string, double> kvp1, KeyValuePair<string, double> kvp2)
			               { return Comparer<double>.Default.Compare(kvp1.Value, kvp2.Value); });
			
			Hashtable degrees = new Hashtable();
			degrees.Add("Sun",     GetDegree("Sun ", output));
			degrees.Add("Moon",    GetDegree("Moon", output));
			degrees.Add("Lilith",  GetDegree("Lili", output));
			degrees.Add("Node",    GetDegree("Node", output));
			degrees.Add("Mercury", GetDegree("Merc", output));
			degrees.Add("Venus",   GetDegree("Venu", output));
			degrees.Add("Mars",    GetDegree("Mars", output));
			degrees.Add("Jupiter", GetDegree("Jupi", output));
			degrees.Add("Saturn",  GetDegree("Satu", output));
			degrees.Add("Uranus",  GetDegree("Uran", output));
			degrees.Add("Neptune", GetDegree("Nept", output));
			degrees.Add("Pluto",   GetDegree("Plut", output));
			degrees.Add("Asc",     GetDegree("House cusp  1", output));
			degrees.Add("SNode",   degrees["Node"]);
			
			Hashtable chartinfo = new Hashtable();
			chartinfo.Add("Ascendant", ascendant);
			chartinfo.Add("Positions", positions);
			chartinfo.Add("Degrees",   degrees);
			
			return chartinfo;
		}
		
		private static double GetPosition(string planet, string output, double asc)
		{
			Hashtable dic = new Hashtable();
			dic.Add("Ari",   0);
			dic.Add("Tau",  30);
			dic.Add("Gem",  60);
			dic.Add("Can",  90);
			dic.Add("Leo", 120);
			dic.Add("Vir", 150);
			dic.Add("Lib", 180);
			dic.Add("Sco", 210);
			dic.Add("Sag", 240);
			dic.Add("Cap", 270);
			dic.Add("Aqu", 300);
			dic.Add("Pis", 330);
			
			Regex reg = new Regex(planet + " ?: +([0-9]+)([a-zA-Z]{3})([0-9]+)");
			
			double deg = Convert.ToDouble(reg.Match(output).Groups[1].Value);
			double sig = Convert.ToDouble(dic[reg.Match(output).Groups[2].Value]);
			double dec = Convert.ToDouble(reg.Match(output).Groups[3].Value) / 100;
			
			return deg + sig + dec - asc;
		}
		
		private static double GetDegree(string planet, string output)
		{
			Regex reg = new Regex(planet + " ?: +([0-9]+)([a-zA-Z]{3})([0-9]+)");
			
			double deg = Convert.ToDouble(reg.Match(output).Groups[1].Value);
			double dec = Convert.ToDouble(reg.Match(output).Groups[3].Value) / 100;
			
			return deg + dec;
		}
		
		private static double Sanitize(double degree)
		{
			if (degree > 360) { degree -= 360; }
			if (degree < 0)   { degree += 360; }
			return degree;
		}
	}
}
